

#coding=utf-8

import asyncio
import numpy as np
import random
import time

envTest =  True #True为windows端的测试环境，False为原型机上的生产环境
if not envTest:
    import RPi.GPIO as GPIO
    GPIO.setmode(GPIO.BCM)



    #*****************GPIO定义******************
    def IO_ctrl(ch,sw):
        pin_GPIO_BCM_A0 = 24
        pin_GPIO_BCM_A1 = 25
        pin_GPIO_BCM_A2 = 5
        pin_GPIO_BCM_EN = 12
        pin_GPIO_BCM_IN = 6

        channel = {"10": 0b1111,  "11":0b1101, "12":0b1011, "13":0b1001, "6":0b0111, "5":0b0101, "4":0b0011, "3":0b0001,"format": "A2A1A0EN"}
        switch = {"on": 0b00, "off":0b11}
        #以下3，4，5，6，11，12，13，14代表焊盘上引脚名, on, off 代表后级选通
        chlist = ["3", "4", "5", "6", "10", "11", "12", "13", "init"]    
        swlist = ["on", "off"]

        if ch not in chlist:
            return 1
        if sw not in swlist:
            return 1

        elif ch == 'init':
            GPIO.setup(pin_GPIO_BCM_EN, GPIO.OUT)
            GPIO.setup(pin_GPIO_BCM_A2, GPIO.OUT)
            GPIO.setup(pin_GPIO_BCM_A1, GPIO.OUT)
            GPIO.setup(pin_GPIO_BCM_A0, GPIO.OUT)
            GPIO.setup(pin_GPIO_BCM_IN, GPIO.OUT)
            GPIO.output(pin_GPIO_BCM_EN, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_A2, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_A1, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_A0, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_IN, GPIO.HIGH)
            return 0

        GPIO.output(pin_GPIO_BCM_EN, GPIO.LOW)
        if sw == 'on':
            GPIO.output(pin_GPIO_BCM_IN, GPIO.LOW)
        else:
            GPIO.output(pin_GPIO_BCM_IN, GPIO.HIGH)
        if channel[ch]&0b0010==0:
            GPIO.output(pin_GPIO_BCM_A0, GPIO.LOW)
        else:
            GPIO.output(pin_GPIO_BCM_A0, GPIO.HIGH)
        if channel[ch]&0b0100==0:
            GPIO.output(pin_GPIO_BCM_A1, GPIO.LOW)
        else:
            GPIO.output(pin_GPIO_BCM_A1, GPIO.HIGH)
        if channel[ch]&0b1000==0:
            GPIO.output(pin_GPIO_BCM_A2, GPIO.LOW)
        else:
            GPIO.output(pin_GPIO_BCM_A2, GPIO.HIGH)
        GPIO.output(pin_GPIO_BCM_EN, GPIO.HIGH)
        return 0

    IO_ctrl('init','off')
    IO_ctrl('11','on')

#******************与硬件通讯的基础模块******************
async def sendmessage(websocket,msg,type='text'):
    import json
    resp = {}
    resp["type"] = type
    resp["value"] = msg
    await websocket.send(json.dumps(resp))

if not envTest:
    import ADS1256
    import DAC8532

if not envTest:
    adc=ADS1256.ADS1256()
    dac=DAC8532.DAC8532()
    adc.ADS1256_init()

    #if DAC8532.DAC_VREF!=5:
        #DAC8532.DAC_VREF=5.18
        #print(f'DAC Vref set to 5.18 V')

    def Output(channel,volt,dac=dac):
        volt=volt * 5.0/4.096# Calibration

        if channel==1: #channel 0 or channel 1
            dac.DAC8532_Out_Voltage(0x34,volt)
        else:
            dac.DAC8532_Out_Voltage(0x30,volt)

allmode = {}
refVg = 0

class Transcurve:
    def __init__(self):
        self.name = 'trans'
        self.fullName = '转移曲线'
        self.defaultPara = {
            'AGND': '2.5',	# given by the particular LDO 
            'cycle':'10', #循环次数
            'reverse':'1',#是否回扫
            'exp_Ids': '0.05',
            'drainV': '0.1',	# ref AGND
            'gateV_begin': '-0.4',	# ref AGND 
            'gateV_end': '0.9',	# ref AGND
            'stepV': '0.01',	# step volt of sweeping
            'stepT': '0.05',	# hold time for each step
            'settleT': '0.1'		# time before sample
        }
        self.c = None #记录剩余循环次数的
        self.changableParams = self.defaultPara
        self.loadpara()

        #eCharts图表的设置参数，包括坐标轴，动画时间，是否显示标记等。
        #熟悉eCharts架构的话可以自由编辑样式。
        self.eChartsSet = '''{
            "xAxis": {
                "name": "Gate V (V)",
                "type": "value",
                "nameLocation": "middle",
                "nameTextStyle": {
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "nameGap": 25,
                "axisLine": {
                    "lineStyle": {
                        "color": "#FFFFFF"
                    }
                },
                "axisLabel": {
                    "fontSize": 14
                },
                "axisTick": {
                    "inside": true
                },
                "splitLine": {
                    "show": false
                },
                "max":'''+ str(self.gateV_begin) + ''',
                "min":'''+ str(self.gateV_end) + '''
            },
            "yAxis": [{
                "type":"value",
                "name": "Drain I (uA)",
                "nameLocation": "middle",
                "nameGap": 30
            },{
                "type":"log",
                "axisLabel":{
                    "formatter":"function(value,index){return Number(value).toExponential();}"
                }
            }],
            "animationDurationUpdate": 100,
            "series": [
                {"showSymbol": false,"data":[],"type":"line","smooth":true,"yAxisIndex":0},
                {"showSymbol": false,"data":[],"type":"line","smooth":true,"yAxisIndex":1},
                {"showSymbol": false,"data":[],"type":"line","smooth":true},
                {"showSymbol": false,"data":[],"type":"line","smooth":true},
                {"showSymbol": false,"data":[],"type":"line","smooth":true},
                {"showSymbol": false,"data":[],"type":"line","smooth":true},
                {"showSymbol": false,"data":[],"type":"line","smooth":true},
                {"showSymbol": false,"data":[],"type":"line","smooth":true}]
        }'''
        
        ##!!!!!!显示曲线的条数取决于series里头有几个{}!!!!!!!!!return的数据如果比这个多不会显示，少了没事。

    def loadpara(self):
        self.AGND = eval(self.changableParams['AGND'])
        self.cycle = eval(self.changableParams['cycle'])
        self.reverse = eval(self.changableParams['reverse'])
        self.drainV = eval(self.changableParams['drainV'])	# ref AGND
        self.gateV_begin = eval(self.changableParams['gateV_begin'])	# ref AGND 
        self.gateV_end = eval(self.changableParams['gateV_end'])	# ref AGND
        self.stepV = eval(self.changableParams['stepV'])	# step volt of sweeping
        self.stepT = eval(self.changableParams['stepT'])	# hold time for each step
        self.settleT = eval(self.changableParams['settleT'])		# time before sample
        self.expIds = eval(self.changableParams['exp_Ids'])
        self.xCounts = 0 #控制坐标轴宽度上限

    async def prepare(self,websocket):   
        self.isreverse = False #用来记录去线是否已经扫完，扫完之后会被修改为True进行回扫。         
        self.pinNum_drain = 0	# DAC pinNum giving drainV
        self.pinNum_source = 0	# ADC pinNum sensing osc 
        self.pinNum_gate = 1	# DAC pinNum giving gateV
        self.pinNum_AGND = 3	# ADC pinNum recaliber AGND
        self.is_sweep_reverse = 0
        #do_abs_Id = False
        self.Vcc = 5
        #kR = 1E6

        global adc
        global Output

        self.vd = self.drainV + self.AGND
        self.vg = self.gateV_begin + self.AGND
        self.ftSettle = self.settleT
        self.ftHold = self.stepT
        self.vmax = self.gateV_end - self.gateV_begin
        self.n = int(self.vmax / self.stepV)	#num of samp
        
        self.rs=[]
        self.X=[]
        self.cur_AGND=[]
        self.Id=[]
        self.Vg=[]
              
        self.expVg=[]
        self.expcnt = 0
        
        #self.refVg = 0
        #***************Sweep Back**************
        if self.is_sweep_reverse:
            self.gateV_begin, self.gateV_end = self.gateV_end, self.gateV_begin
        

        #****************Set Starting Voltage***************
        await sendmessage(websocket, '初始化中，请勿停止或退出模式')
        self.set_step = 0.01
        self.set_times_vg = int(self.gateV_begin/self.set_step)
        self.set_times_vd = int(self.drainV/self.set_step)

        if not envTest:
            await asyncio.sleep(self.ftSettle)
            for u in range(abs(self.set_times_vg)):
                Output(self.pinNum_gate,  2.5 + u/abs(self.set_times_vg) * self.gateV_begin)
                await asyncio.sleep(self.ftHold)

            for v in range(abs(self.set_times_vd)):
                Output(self.pinNum_drain,  2.5 + v/abs(self.set_times_vd) * self.drainV)
                await asyncio.sleep(self.ftHold)
            
            await asyncio.sleep(5)
            await sendmessage(websocket, '初始化结束，开始采样')
        #***************AGND Pre-sampling**************
        
            self.preAGND = []
            self.nPreset = int(self.ftSettle / self.ftHold)
            for i in range(self.nPreset):
                self.r = adc.ADS1256_GetAll()
                self.preAGND.append(self.r[self.pinNum_AGND] * self.Vcc / 0x7fffff)
                await asyncio.sleep(self.ftHold)
        
            self.averAGND = np.mean(self.preAGND)
            self.AGND = self.averAGND
            self.vd = self.drainV + self.AGND
            self.vg = self.gateV_begin + self.AGND
            Output(self.pinNum_gate, self.vg)
            Output(self.pinNum_drain, self.vd)
            

        #for k in range(10):
            #await asyncio.sleep(self.ftSettle)
            #k += 1
            
        await asyncio.sleep(self.ftSettle)
        self.lastAGND = self.AGND
        #loopI和loopN是控制循环的变量，通过continueLoop定义循环进行的方式
        self.loopI = 0
        self.loopN = self.n 

    
    def isContinue(self):
        #用于判断循环是否继续的表达式
        if self.reverse == 1:
            if self.isreverse == False:
                if self.loopI >= self.loopN:
                    self.isreverse = True #去线扫描完成后，开始扫回线。
                return True
            else:
                return self.loopI > 0

        else:
            return self.loopI < self.loopN
    def afterLoop(self):
        #单次循环之后的变量修改
        if self.isreverse == False:
            self.loopI += 1
        else:
            self.loopI -= 1

    async def loopBody(self,websocket,i=None,n=None):
        #载入循环控制变量
        if i == None:
            i = self.loopI
        if n == None:
            n = self.loopN
        #*************循环采集数据时自定义的代码*****************************
        self.X.append(i * self.vmax / n + self.gateV_begin)
        if not envTest:
            Output(self.pinNum_drain, self.drainV + self.lastAGND)
            Output(self.pinNum_gate, i * self.vmax / n + self.vg)
            self.r=adc.ADS1256_GetAll()
            self.rs.append(self.r[self.pinNum_source] * self.Vcc / 0x7fffff)
            self.Vg.append(self.r[6] * self.Vcc / 0x7fffff - self.AGND)
            self.cur_AGND.append(self.r[self.pinNum_AGND] * self.Vcc / 0x7fffff)
            self.lastAGND = self.cur_AGND[-1]
            self.Id.append((self.rs[-1] - self.cur_AGND[-1]))
            
            global refVg
            if self.Id[-1] <= self.expIds and self.expcnt <=3:
                self.expVg.append(i*self.vmax / n + self.vg)
                self.expcnt += 1
            elif self.Id[-1] <= self.expIds and self.expcnt == 4: 
                refVg = self.expVg[0]
                #self.expVg.clear()
                self.expcnt = 0
            else:
                self.expVg.clear()
                self.expcnt = 0

        await asyncio.sleep(self.ftHold)

        #*******************************************************************
        #输出的数据及格式，envTest为True时输出的是随机产生的模拟数据
        ##!!!!!!如果显示多条曲线可以用类似的结构，记得修改init部分self.option里的内容。
        if envTest:
            tempData = random.random() ** 5+0.00001
            return "[{}, {:.4}, {:.4}]".format(self.X[-1],tempData,tempData)
        else:
            return "[{}, {}]".format(self.Vg[-1],self.Id[-1],self.Id[-1])
    
    #循环结束后的操作
    async def endLoop(self,websocket):
        #****************Set Ending Voltage**********
        await sendmessage(websocket, '复位中，请勿停止或退出模式')
        self.reset_step = 0.01
        self.reset_times_vg = int(self.gateV_end/self.reset_step)
        self.reset_times_vd = int(self.drainV/self.reset_step)

        if not envTest:
            await asyncio.sleep(self.ftSettle)
            for i in range(abs(self.reset_times_vg)):
                Output(self.pinNum_gate, (self.gateV_end + 2.5) - i/abs(self.reset_times_vg)*self.gateV_end)
                await asyncio.sleep(self.ftHold)

            for k in range(abs(self.reset_times_vd)):
                Output(self.pinNum_drain, (self.drainV + 2.5)- k/abs(self.reset_times_vd)* self.drainV)
                await asyncio.sleep(self.ftHold)

            Output(self.pinNum_drain, 2.5)
            Output(self.pinNum_gate, 2.5)

            await asyncio.sleep(self.ftSettle)
        #这里要重置loopI的值 
        self.loopI = 0       
        await sendmessage(websocket, '复位完毕，允许停止或退出模式')
#将定义的工作模式放入allmode中，可以通过注释来开启和关闭这个工作模式
allmode['#trans'] = Transcurve()

class Idvt:
    def __init__(self):
        self.name = 'idvt'
        self.fullName = '电流时间'

        self.defaultPara = {
            'AGND' : '2.5',	# given by the particular LDO 
            'drainV' : '0.1',	# ref AGND
            #'gateV' : '0',	#ref AGND
            'stepT' : '0.1',	# step volt of sweeping
            'settleT' : '2',		# time before sample
            'x_width' : '30'		# time before sample
        }
        self.changableParams = self.defaultPara
        self.loadpara()

        #eCharts图表的设置参数，包括坐标轴，动画时间，是否显示标记等。
        #熟悉eCharts架构的话可以自由编辑样式。
        self.eChartsSet = r'''{
            "xAxis": {
                "name": "时间(s)",
                "type": "time",
                "nameLocation": "middle",
                "nameTextStyle": {
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "nameGap": 28,
                "axisLine": {
                    "lineStyle": {
                        "color": "#FFFFFF"
                    }
                },
                "axisLabel": {
                    "fontSize": 14,
                    "formatter": "{ss}"
                },
                "axisTick": {
                    "inside": true
                },
                "splitLine": {
                    "show": false
                }
            },
            "yAxis": {
                "name": "电流(uA)",
                "nameLocation": "end",
                "nameGap": 15
            },
            "animationDurationUpdate": 0,
            "series": [
                {"showSymbol": false,"data":[],"type":"line","smooth":true}]
        }
        '''

    def loadpara(self):
        self.AGND = eval(self.changableParams['AGND'])
        self.drainV = eval(self.changableParams['drainV'])	# ref AGND
        #self.gateV = eval(self.changableParams['gateV'])	# ref AGND
        self.stepT = eval(self.changableParams['stepT'])	# hold time for each step
        self.settleT = eval(self.changableParams['settleT']) # time before sample
        self.xCounts = eval(self.changableParams['x_width'])/self.stepT #控制坐标轴宽度上限

    async def prepare(self,websocket):
        #先跑一遍转移曲线
        wMode = allmode['#trans']
        tempReverse = wMode.reverse
        wMode.reverse = 0#防止回扫
        await wMode.prepare(websocket)
        while wMode.isContinue():
            await wMode.loopBody(websocket)
            wMode.afterLoop()
            await sendmessage(websocket,'{}%'.format(int(wMode.loopI/wMode.loopN*100)),'trans')
        await wMode.endLoop(websocket)
        wMode.reverse = tempReverse#还原原始设定。
        #***************Var Decl. and Init.**************
        global refVg
        self.gateV = refVg    
        await sendmessage(websocket, 'ExpVg: ' + '{:.3}'.format(refVg-2.5))    
        self.pinNum_drain = 0	# DAC pinNum giving drainV
        self.pinNum_source = 0	# ADC pinNum sensing osc 
        self.pinNum_gate = 1	# DAC pinNum giving gateV
        self.pinNum_AGND = 3	# ADC pinNum recaliber AGND
        #self.is_sweep_reverse = 0
        #do_abs_Id = False
        self.Vcc = 5
        #kR = 1E6
        self.tare = 0

        global adc
        global Output

        self.vd = self.drainV + self.AGND
        self.vg = self.gateV
        self.ftSettle = self.settleT
        self.ftHold = self.stepT
        
        self.rs=[]
        self.X=[]
        self.cur_AGND=[]
        self.Id=[]
        self.Id_tared = []
        self.Vg=[]
        self.percent=[] 

        #****************Set Starting Voltage************
        await sendmessage(websocket, '初始化中，请勿停止或退出模式')
        self.set_step = 0.01
        self.set_times_vg = int((self.gateV - 2.5)/self.set_step)
        self.set_times_vd = int(self.drainV/self.set_step)

        if not envTest:
            await asyncio.sleep(self.ftSettle)
            for u in range(abs(self.set_times_vg)):
                Output(self.pinNum_gate,  2.5 + u/abs(self.set_times_vg) * (self.gateV - 2.5))
                await asyncio.sleep(self.ftHold)

            for v in range(abs(self.set_times_vd)):
                Output(self.pinNum_drain,  2.5 + v/abs(self.set_times_vd) * self.drainV)
                await asyncio.sleep(self.ftHold)
            
            await asyncio.sleep(5)
            await sendmessage(websocket, '初始化结束，开始采样')
        #***************AGND Pre-sampling**************
        
            self.preAGND = []
            self.nPreset = int(self.ftSettle / self.ftHold)
            for i in range(self.nPreset):
                self.r = adc.ADS1256_GetAll()
                self.preAGND.append(self.r[self.pinNum_AGND] * self.Vcc / 0x7fffff)
                await asyncio.sleep(self.ftHold)
        
            self.averAGND = np.mean(self.preAGND)
            self.AGND = self.averAGND
            self.vd = self.drainV + self.AGND
            self.vg = self.gateV
            Output(self.pinNum_gate, self.vg)
            Output(self.pinNum_drain, self.vd)
        await asyncio.sleep(self.ftSettle)
        await sendmessage(websocket,'Gogogo!','start')
        self.timeOrigin = time.time()
        #loopI和loopN是控制循环的变量，通过continueLoop定义循环进行的方式
        self.loopI = 0
        self.loopN = 0

    
    def isContinue(self):
        #用于判断循环是否继续的表达式
        return True#电流时间模式为无限循环，直到人工暂停或者停止
    def afterLoop(self):
        #单次循环之后的变量修改
        self.loopI += 1

    async def loopBody(self,websocket,i=None,n=None):
        self.stop = 1
        #载入循环控制变量
        if i == None:
            i = self.loopI
        if n == None:
            n = self.loopN
        #*************循环采集数据时自定义的代码*****************************
        self.X.append(i * self.stepT)
        if not n == 'tare':#'tare'命令下不等待
            await asyncio.sleep(self.ftHold)
        if not envTest:
            Output(self.pinNum_gate, self.vg)
            Output(self.pinNum_drain, self.vd)
            self.r=adc.ADS1256_GetAll()
            self.rs.append(self.r[self.pinNum_source] * self.Vcc / 0x7fffff)
            self.cur_AGND.append(self.r[self.pinNum_AGND] * self.Vcc / 0x7fffff)           
            self.Id.append((self.rs[-1] - self.cur_AGND[-1]))
            self.Id_tared.append((self.rs[-1] - self.cur_AGND[-1]- self.tare))
            self.Vg.append(self.r[6] * self.Vcc / 0x7fffff)

            
            if self.Id[-1] < 0:
                self.Id[-1] = 0
        if n == 'tare':
            if envTest:
                self.tare = 0
            else:
                self.tare = self.Id[-1]
            await sendmessage(websocket, '{}'.format(self.tare),'tare')
            return '{}'.format(self.tare)
        #*******************************************************************
        #输出的数据及格式，envTest为True时输出的是随机产生的模拟数据
        timepassed = time.time() - self.timeOrigin
        if not envTest and (self.X[-1] <= self.stop):
            return "[{}, {}, {}, {}, {}, {}]".format(timepassed*1000,self.Id[-1],self.X[-1]*1000,self.tare , self.Id_tared[-1],refVg-2.5)
        elif not envTest and (self.X[-1] > self.stop):
            return "[{}, {}, {}, {}, {}, {}]".format(timepassed*1000,self.Id[-1],self.X[-1]*1000,self.tare , self.Id_tared[-1],refVg-2.5)
        else:
            return "[{}, {:.3}, {:.3},{:.3}]".format(timepassed*1000,random.random(),random.random(),random.random())

    #循环结束后的操作
    async def endLoop(self,websocket):
        #这里要重置loopI的值 
        await asyncio.sleep(self.ftSettle)
        self.loopI = 0   
        self.tare = 0
        
        #**************Set Ending Voltage*************
        await sendmessage(websocket, '复位中，请勿停止或退出模式')
        self.reset_step = 0.01
        self.reset_times_vg = int((self.gateV - 2.5)/self.reset_step)
        self.reset_times_vd = int(self.drainV/self.reset_step)

        if not envTest:
            for i in range(abs(self.reset_times_vg)):
                Output(self.pinNum_gate, self.gateV - i/abs(self.reset_times_vg)*(self.gateV - 2.5))
                await asyncio.sleep(self.ftHold)

            for k in range(abs(self.reset_times_vd)):
                Output(self.pinNum_drain, (self.drainV + 2.5)- k/abs(self.reset_times_vd)* self.drainV)
                await asyncio.sleep(self.ftHold)

        await asyncio.sleep(self.ftSettle)
        await sendmessage(websocket, '复位结束，请勿停止或退出模式')
#将定义的工作模式放入allmode中，可以通过注释来开启和关闭这个工作模式
allmode['#idvt'] = Idvt()


class RandomData:
    def __init__(self):
        self.name = 'rnd'
        self.fullName = '模拟数据'
        self.defaultPara = {
            'start' : '50',	#随机数开始
            'jump' : '5',	#随机增减的范围
            'max':'100',#上限
            'min':'0',#下限
            'stepT' : '0.1',	#产生一个随机数的时间
            'x_width' : '10'# time before sample
        }
        self.changableParams = self.defaultPara
        self.loadpara()

        #eCharts图表的设置参数，包括坐标轴，动画时间，是否显示标记等。
        #熟悉eCharts架构的话可以自由编辑样式。
        self.eChartsSet = r'''{
            "xAxis": {
                "name": "时间(s)",
                "type": "time",
                "nameLocation": "middle",
                "nameTextStyle": {
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "nameGap": 28,
                "axisLine": {
                    "lineStyle": {
                        "color": "#FFFFFF"
                    }
                },
                "axisLabel": {
                    "fontSize": 14,
                    "formatter": "{ss}"
                },
                "axisTick": {
                    "inside": true
                },
                "splitLine": {
                    "show": false
                }
            },
            "yAxis": {
                "name": "模拟数据",
                "nameLocation": "end",
                "nameGap": 15
            },
            "animationDurationUpdate": 0,
            "series": [{
                "showSymbol": false,
                "data":[],
                "type":"line"
            }]
        }
        '''

    def loadpara(self):
        self.start = eval(self.changableParams['start'])
        self.jump = eval(self.changableParams['jump'])	# ref AGND
        self.max = eval(self.changableParams['max'])	# ref AGND
        self.min = eval(self.changableParams['min'])	# hold time for each step
        self.stepT = eval(self.changableParams['stepT']) # time before sample
        self.xCounts = eval(self.changableParams['x_width'])/self.stepT #控制坐标轴宽度上限

    #循环开始时的准备
    async def prepare(self,websocket):
        self.numNow = self.start
        #loopI和loopN是控制循环的变量，通过continueLoop定义循环进行的方式
        self.loopI = 0
        self.loopN = 0
        await asyncio.sleep(0.2)

    def isContinue(self):
        #用于判断循环是否继续的表达式
        return True#电流时间模式为无限循环，直到人工暂停或者停止
    def afterLoop(self):
        #单次循环之后的变量修改
        self.loopI += 1

    async def loopBody(self,websocket,i=None,n=None):
        #载入循环控制变量
        if i == None:
            i = self.loopI
        if n == None:
            n = self.loopN
        #*************循环采集数据时自定义的代码*****************************
        import random
        res = self.numNow + random.random()*self.jump - 0.5*self.jump
        if res> self.max: res = self.max
        if res< self.min: res = self.min
        self.numNow = res 
        await asyncio.sleep(self.stepT)
        #*******************************************************************
        #输出的数据及格式
        return "[{}, {}]".format(i*self.stepT*1000,res)
    
    #循环结束后的操作
    async def endLoop(self,websocket):
        #这里要重置loopI的值 
        self.loopI = 0   

#将定义的工作模式放入allmode中，可以通过注释来开启和关闭这个工作模式
allmode['#rnd'] = RandomData()

class DeviceSet:
    def __init__(self):
        self.name = 'set'
        self.fullName = '采样设置'
        self.defaultPara = {
            '稳定时间' : '180',	
            '采样时间' : '120',	#随机增减的范围
        }
        self.changableParams = self.defaultPara
        self.loadpara()

        #eCharts图表的设置参数，包括坐标轴，动画时间，是否显示标记等。
        #熟悉eCharts架构的话可以自由编辑样式。
        self.eChartsSet = r'''{
            
        }
        '''

    def loadpara(self):
        None
        
                #循环开始时的准备
    async def prepare(self,websocket):
        None

    def isContinue(self):
        #用于判断循环是否继续的表达式
        return False#电流时间模式为无限循环，直到人工暂停或者停止
    def afterLoop(self):
        #单次循环之后的变量修改
        None

    async def loopBody(self,websocket,i=None,n=None):
        #载入循环控制变量
        return "[{}, {}]".format(0,0)
    
    #循环结束后的操作
    async def endLoop(self,websocket): 
        None  

#将定义的工作模式放入allmode中，可以通过注释来开启和关闭这个工作模式
allmode['#set'] = DeviceSet()

#**********************运行参数的读取，设置，保存模块*************
import os
def modeConfig(mode='get',conf=None):
    if mode == 'get':
        res = {}
        for key in allmode.keys():
            name = allmode[key].name
            res[name] = {}
            res[name]['name'] = allmode[key].fullName
            res[name]['para'] = allmode[key].changableParams
        return res
    elif mode == 'default':
        for key in allmode.keys():
            allmode[key].changableParams = allmode[key].defaultPara
        return modeConfig()
    elif mode == 'set':
        for key in conf:
            #如果载入参数失败会自动读取默认参数
            try:
                allmode['#'+key].changableParams = conf[key]['para']
                allmode['#'+key].loadpara()
            except:
                None

#读取config.ini配制文件，如果没有找到配制文件，则读取默认配制参数。    
def savepara():
    import json
    f = open('config.ini','w')
    json.dump(modeConfig(),f)
    f.close()
def loadpara():
    if not os.path.isfile('config.ini'):
        savepara()
    else:
        import json
        f = open('config.ini','r')
        Params = json.load(f)
        modeConfig('set',Params)
        f.close()
        savepara()




